package com.TanNgee.remoting.transport.socket;

import com.TanNgee.config.CustomShutdownHook;
import com.TanNgee.config.RpcServiceConfig;
import com.TanNgee.factory.SingletonFactory;
import com.TanNgee.provider.ServiceProvider;
import com.TanNgee.provider.impl.ZkServiceProviderImpl;
import com.TanNgee.utils.concurrent.threadpool.ThreadPoolFactoryUtil;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutorService;

import static com.TanNgee.remoting.transport.netty.server.NettyRpcServer.PORT;

/**
 * 用于等待客户端连接。当客户端成功连接之后，就可以发送 rpc 请求(RpcRequest) 到服务端了。
 * 然后，服务端拿到 RpcRequest就会去执行对应的方法。
 * 执行完对应的方法之后，就把执行得到的结果放在 RpcResponse 中返回给客户端
 *
 * @author 陈毅
 * @create 2022/3/21 0:08
 */
@Slf4j
public class SocketRpcServer {

    private final ExecutorService threadPool;
    private final ServiceProvider serviceProvider;

    public SocketRpcServer() {

        // 获取线程池
        threadPool = ThreadPoolFactoryUtil.createCustomThreadPoolIfAbsent("socket-server-rpc-pool");

        serviceProvider = SingletonFactory.getInstance(ZkServiceProviderImpl.class);
    }

    public void registerService(RpcServiceConfig rpcServiceConfig) {
        serviceProvider.publishService(rpcServiceConfig);
    }

    public void start() {
        try (ServerSocket server = new ServerSocket()) {
            String host = InetAddress.getLocalHost().getHostAddress();
            server.bind(new InetSocketAddress(host, PORT));

            // 服务启动前，清除掉所有已经存在的服务
            CustomShutdownHook.getCustomShutdownHook().clearAll();

            Socket socket;
            while ((socket = server.accept()) != null) {
                log.info("client connected [{}]", socket.getInetAddress());

                // 创建新的与客户端通信的线程，并且放入线程池中
                threadPool.execute(new SocketRpcRequestHandlerRunnable(socket));
            }

            threadPool.shutdown();
        } catch (IOException e) {
            log.error("occur IOException:", e);
        }
    }
}
